package com.youlu.campus.service.activity;

import com.youlu.campus.entity.ActivityChannelHourPVUVStatistics;
import com.youlu.campus.entity.VO.res.ActivityChannelPvUvRes;
import lombok.extern.slf4j.Slf4j;
import ma.glasnost.orika.MapperFacade;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.FindAndModifyOptions;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;


import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.TextStyle;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ActivityChannelHourPVUVService {

    @Autowired
    private MongoTemplate mongoTemplate;

    private static final String ACTIVITY_CHANNEL_USER_HOUR_UV = "activity:%s:channel:%s:user:%s:day.hour:%s:uv";

    @Autowired
    private MapperFacade mapperFacade;


    public List<ActivityChannelPvUvRes> list(Query query){
        query.with(Sort.by(Sort.Direction.ASC,"dayDate"));
        List<ActivityChannelHourPVUVStatistics> list = this.mongoTemplate.find(query, ActivityChannelHourPVUVStatistics.class);
        if(CollectionUtils.isEmpty(list)){
            return null;
        }
        return list.stream().map(pvUv->{
            ActivityChannelPvUvRes activityChannelPvUv = mapperFacade.map(pvUv,ActivityChannelPvUvRes.class);
            activityChannelPvUv.setDateSort(pvUv.getDate()+" "+pvUv.getHourOfDate());
            return activityChannelPvUv;
        }).collect(Collectors.toList()).stream().sorted(Comparator.comparing(ActivityChannelPvUvRes::getDateSort)).collect(Collectors.toList());
    }


    @Async
    public void setHourOfDaySignUp(String activityId, String channelCode){
        log.info("【渠道hourOfDay 报名人数】activityId:{},channelCode:{},userClientCookie", activityId, channelCode);
        String nowDate = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String dayHour = LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH"));
        Integer currentDate = Integer.valueOf(nowDate);
        Query query = new Query();
        query.addCriteria(Criteria.where("activityId").is(activityId));
        query.addCriteria(Criteria.where("channelCode").is(channelCode));
        query.addCriteria(Criteria.where("dayDate").is(currentDate));
        query.addCriteria(Criteria.where("hourOfDate").is(dayHour));
        Update update = new Update();
        update.inc("signUpCount", 1);
        this.mongoTemplate.updateFirst(query, update, ActivityChannelHourPVUVStatistics.class);
    }


    @Async
    public void doSetPVUV(String activityId, String channelCode, String userClientCookie) {
        log.info("【渠道hourOfDayPVUV】activityId:{},channelCode:{},userClientCookie", activityId, channelCode,
                userClientCookie);
        String nowDate = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String dayHour = LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH"));
        String dateNow = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        String dayOfWeek = LocalDate.now().getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.CHINA);
        Integer currentDate = Integer.valueOf(nowDate);
        Query query = new Query();
        query.addCriteria(Criteria.where("activityId").is(activityId));
        query.addCriteria(Criteria.where("channelCode").is(channelCode));
        query.addCriteria(Criteria.where("dayDate").is(currentDate));
        query.addCriteria(Criteria.where("hourOfDate").is(dayHour));
        Update update = new Update();
        update.inc("pvCount", 1);
        String userUVKey = String.format(ACTIVITY_CHANNEL_USER_HOUR_UV, activityId, channelCode, userClientCookie, nowDate+dayHour);
        if(setUV(userUVKey)){
            update.inc("uvCount", 1);
        }
        update.set("dayOfWeek", dayOfWeek);
        update.set("date", dateNow);
        boolean exists = this.mongoTemplate.exists(query, ActivityChannelHourPVUVStatistics.class);
        if (!exists) {
            Date now = new Date();
            update.setOnInsert("createdTime", now);
            FindAndModifyOptions findAndModifyOptions = new FindAndModifyOptions();
            findAndModifyOptions.returnNew(Boolean.TRUE);
            findAndModifyOptions.upsert(Boolean.TRUE);
            this.mongoTemplate.findAndModify(query, update, findAndModifyOptions, ActivityChannelHourPVUVStatistics.class);
            return;
        }
        this.mongoTemplate.updateFirst(query, update, ActivityChannelHourPVUVStatistics.class);
    }

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    private Boolean setUV(String userUvKey) {
        // 推荐：原子地 setIfAbsent + 过期（毫秒）
        Boolean isNew = redisTemplate.opsForValue().setIfAbsent(
                userUvKey,
                "1",
                Duration.ofMillis(3600_000L) //  1xiaoshi
        );
        return Boolean.TRUE.equals(isNew);
    }
}
